import tkinter as tk
from tkinter import ttk, scrolledtext, filedialog, messagebox
import socket
import threading
import time
import json
import os
from datetime import datetime

class NetworkDebugger:
    def __init__(self, root):
        self.root = root
        self.root.title("高级网络调试助手")
        self.root.geometry("1400x800")
        
        # 协议与模式变量
        self.protocol_var = tk.StringVar(value="TCP")  # 默认TCP
        self.mode_var = tk.StringVar(value="客户端")    # 默认TCP客户端
        
        # 中文字体配置
        self.style = ttk.Style()
        self.style.configure("TLabel", font=("SimHei", 10))
        self.style.configure("TButton", font=("SimHei", 10))
        self.style.configure("TCombobox", font=("SimHei", 10))
        self.style.configure("TCheckbutton", font=("SimHei", 10))
        
        # 网络核心变量
        self.socket = None                # 主套接字
        self.running = False              # 运行状态标记
        self.connections = []             # 存储TCP服务器的所有客户端连接（含IP、端口、连接对象）
        self.main_connection = None       # 当前选中的发送目标连接
        self.selected_client_idx = -1     # 选中的客户端索引（-1表示"所有客户端"）
        self.clients_expanded = True      # 客户端列表默认展开
        
        # 数据显示与发送相关
        self.received_data_history = []   # 接收/发送数据历史
        self.display_mode_var = tk.StringVar(value="ASCII")  # 显示模式：ASCII/Hex
        self.hex_send_var = tk.BooleanVar(value=False)       # 十六进制发送开关
        self.append_newline_var = tk.BooleanVar(value=True)  # 自动换行开关
        self.send_buffer = ""             # 发送框原始数据缓存
        
        # 自动应答相关
        self.auto_responses = []          # 自动应答规则列表
        self.auto_response_enabled = tk.BooleanVar(value=False)  # 自动应答总开关
        self.select_all_var = tk.BooleanVar(value=False)         # 规则全选开关
        self.rule_vars = []               # 存储规则变量，解决勾选不准确问题
        
        # 快捷指令相关
        self.shortcut_commands = []       # 快捷指令列表
        self.shortcut_select_all_var = tk.BooleanVar(value=False)  # 快捷指令全选开关
        self.shortcut_vars = []           # 存储快捷指令变量，解决勾选不准确问题
        
        # Debug与状态变量
        self.debug_mode_var = tk.BooleanVar(value=False)  # Debug模式开关
        self.status_var = tk.StringVar(value="未启动")    # 状态提示文本
        
        # IP与端口配置（默认值）
        self.local_ip_var = tk.StringVar(value="0.0.0.0")
        self.local_port_var = tk.StringVar(value="8080")
        self.remote_ip_var = tk.StringVar(value="127.0.0.1")
        self.remote_port_var = tk.StringVar(value="8080")  # TCP服务器模式下为"监听端口"
        
        # 初始化界面
        self.create_widgets()
        
        # 初始化自动应答规则（至少保留1行空规则）
        if not self.auto_responses:
            self.auto_responses.append({
                "priority": 1, "pattern": "", "pattern_is_hex": False,
                "response": "", "response_is_hex": False, "remark": "",
                "enabled": True, "selected": False,
                "pattern_buffer": "", "response_buffer": ""
            })
        
        # 初始化快捷指令（至少保留1行空指令）
        if not self.shortcut_commands:
            self.shortcut_commands.append({
                "name": "指令1", "content": "", "is_hex": False,
                "enabled": True, "selected": False, "temp_buffer": ""
            })
        
        # 加载历史配置
        self.load_config()
        
        # 绑定窗口关闭事件
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        
        # 延迟初始化UI，确保所有组件都已创建
        self.root.after(100, self.post_init_ui)
    
    def post_init_ui(self):
        """初始化完成后执行的UI调整，解决首次显示问题"""
        # 强制刷新UI布局
        self.update_ui()
        # 确保客户端列表可见
        if self.protocol_var.get() == "TCP" and self.mode_var.get() == "服务器":
            self.client_list_frame.pack(fill=tk.X, pady=(0, 5))
            self.update_clients_list()
            # 触发一次布局更新
            self.root.update_idletasks()
            # 确保发送区域有足够高度
            self.send_frame.update_idletasks()
            self.send_frame.configure(height=self.send_frame.winfo_height())
        
        # 初始显示右侧功能
        self.update_response_rules_ui()
        self.update_shortcut_commands_ui()
    
    def create_widgets(self):
        # 主窗口分栏（左右布局：左侧功能区，右侧选项卡区域）
        main_paned = ttk.PanedWindow(self.root, orient=tk.HORIZONTAL)
        main_paned.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # ---------------------- 左侧主功能区 ----------------------
        left_frame = ttk.Frame(main_paned)
        main_paned.add(left_frame, weight=3)
        
        # 1. 连接配置区域
        config_frame = ttk.LabelFrame(left_frame, text="连接配置", padding="10")
        config_frame.pack(fill=tk.X, pady=(5, 5), padx=5)
        
        # 1.1 协议与模式选择（第一行）
        row1 = ttk.Frame(config_frame)
        row1.pack(fill=tk.X, pady=(0, 10))
        
        # 协议选择（TCP/UDP）
        ttk.Label(row1, text="协议:").pack(side=tk.LEFT, padx=(0, 5))
        protocol_frame = ttk.Frame(row1)
        protocol_frame.pack(side=tk.LEFT, padx=(0, 20))
        ttk.Radiobutton(
            protocol_frame, text="TCP", variable=self.protocol_var, 
            value="TCP", command=self.update_ui
        ).pack(side=tk.LEFT, padx=5)
        ttk.Radiobutton(
            protocol_frame, text="UDP", variable=self.protocol_var, 
            value="UDP", command=self.update_ui
        ).pack(side=tk.LEFT, padx=5)
        
        # TCP模式选择（客户端/服务器）
        self.mode_label = ttk.Label(row1, text="模式:")
        self.mode_frame = ttk.Frame(row1)
        ttk.Radiobutton(
            self.mode_frame, text="客户端", variable=self.mode_var, 
            value="客户端", command=self.update_ui
        ).pack(side=tk.LEFT, padx=5)
        ttk.Radiobutton(
            self.mode_frame, text="服务器", variable=self.mode_var, 
            value="服务器", command=self.update_ui
        ).pack(side=tk.LEFT, padx=5)
        
        # 1.2 IP与端口配置（第二行）
        row2 = ttk.Frame(config_frame)
        row2.pack(fill=tk.X, pady=(0, 10))
        
        # 本地IP/端口（TCP服务器/UPD模式显示）
        self.local_ip_label = ttk.Label(row2, text="本地IP:")
        self.local_ip_entry = ttk.Entry(row2, textvariable=self.local_ip_var, width=15)
        self.local_port_label = ttk.Label(row2, text="本地端口:")
        self.local_port_entry = ttk.Entry(row2, textvariable=self.local_port_var, width=8)
        
        # 远程IP/监听端口（TCP客户端：远程IP/端口；TCP服务器：监听端口）
        self.remote_ip_label = ttk.Label(row2, text="远程IP:")
        self.remote_ip_entry = ttk.Entry(row2, textvariable=self.remote_ip_var, width=15)
        self.remote_port_label = ttk.Label(row2, text="远程/监听端口:")  # 明确端口用途
        self.remote_port_entry = ttk.Entry(row2, textvariable=self.remote_port_var, width=8)
        
        # 1.3 控制按钮与状态（第三行）
        row3 = ttk.Frame(config_frame)
        row3.pack(fill=tk.X)
        
        # 启动/停止按钮
        self.control_btn = ttk.Button(row3, text="连接", command=self.toggle_connection)
        self.control_btn.pack(side=tk.LEFT, padx=(10, 0), pady=5)
        
        # 状态显示（红色：未启动/错误；绿色：运行中）
        self.status_label = ttk.Label(row3, textvariable=self.status_var, foreground="red")
        self.status_label.pack(side=tk.LEFT, padx=(10, 0), pady=5)
        
        # 2. 数据显示区域（支持ASCII/Hex切换、日志保存）
        display_paned = ttk.PanedWindow(left_frame, orient=tk.VERTICAL)
        display_paned.pack(fill=tk.BOTH, expand=True, pady=(5, 5), padx=5)
        
        display_frame = ttk.LabelFrame(display_paned, text="数据显示", padding="10")
        display_paned.add(display_frame, weight=3)
        
        # 2.1 显示控制栏
        display_ctrl = ttk.Frame(display_frame)
        display_ctrl.pack(fill=tk.X, pady=(0, 5))
        
        # 显示模式（ASCII/Hex）
        ttk.Label(display_ctrl, text="显示模式:").pack(side=tk.LEFT, padx=(0, 5))
        mode_frame = ttk.Frame(display_ctrl)
        mode_frame.pack(side=tk.LEFT, padx=(0, 15))
        ttk.Radiobutton(
            mode_frame, text="ASCII", variable=self.display_mode_var, 
            value="ASCII", command=self.refresh_display
        ).pack(side=tk.LEFT, padx=5)
        ttk.Radiobutton(
            mode_frame, text="Hex", variable=self.display_mode_var, 
            value="Hex", command=self.refresh_display
        ).pack(side=tk.LEFT, padx=5)
        
        # 时间戳开关
        self.timestamp_var = tk.BooleanVar(value=True)
        ttk.Checkbutton(
            display_ctrl, text="显示时间戳", variable=self.timestamp_var, 
            command=self.refresh_display
        ).pack(side=tk.LEFT, padx=5)
        
        # Debug模式开关
        ttk.Checkbutton(
            display_ctrl, text="显示调试信息", variable=self.debug_mode_var, 
            command=self.refresh_display
        ).pack(side=tk.RIGHT, padx=15)
        
        # 日志操作（保存/清空）
        ttk.Button(display_ctrl, text="清空", command=self.clear_display).pack(side=tk.RIGHT, padx=5)
        ttk.Button(display_ctrl, text="保存", command=self.save_log).pack(side=tk.RIGHT, padx=5)
        
        # 2.2 数据显示文本框（带滚动条）
        self.display_area = scrolledtext.ScrolledText(
            display_frame, wrap=tk.WORD, font=("SimHei", 10)
        )
        self.display_area.pack(fill=tk.BOTH, expand=True)
        self.display_area.config(state=tk.DISABLED)  # 默认只读
        
        # 文本颜色标签（区分接收/发送/错误/调试信息）
        self.display_area.tag_configure("received", foreground="blue")    # 接收数据
        self.display_area.tag_configure("sent", foreground="green")      # 发送数据
        self.display_area.tag_configure("error", foreground="red")       # 错误信息
        self.display_area.tag_configure("debug", foreground="orange", font=("SimHei", 9, "italic"))  # 调试信息
        
        # 3. 发送数据区域（含客户端列表选择）
        self.send_frame = ttk.LabelFrame(display_paned, text="发送数据", padding="10")
        display_paned.add(self.send_frame, weight=1)
        
        # 3.1 发送控制栏
        send_ctrl = ttk.Frame(self.send_frame)
        send_ctrl.pack(fill=tk.X, pady=(0, 5))
        
        # 十六进制发送开关
        ttk.Checkbutton(
            send_ctrl, text="十六进制发送", variable=self.hex_send_var,
            command=self.toggle_hex_send
        ).pack(side=tk.LEFT, padx=5)
        
        # 自动换行开关
        ttk.Checkbutton(
            send_ctrl, text="自动换行", variable=self.append_newline_var
        ).pack(side=tk.LEFT, padx=5)
        
        # 广播按钮（仅TCP服务器模式显示）
        self.broadcast_btn = ttk.Button(
            send_ctrl, text="广播到所有", command=self.broadcast_data
        )
        
        # 清空发送框按钮
        ttk.Button(
            send_ctrl, text="清空发送框", command=self.clear_send_entry
        ).pack(side=tk.RIGHT, padx=5)
        
        # 3.2 发送文本框
        self.send_entry = scrolledtext.ScrolledText(
            self.send_frame, wrap=tk.WORD, height=3, font=("SimHei", 10)
        )
        self.send_entry.pack(fill=tk.BOTH, expand=True, pady=(0, 5))
        
        # 3.3 客户端列表（TCP服务器模式核心：显示客户端IP和端口）
        self.client_list_frame = ttk.LabelFrame(self.send_frame, text="客户端列表（TCP服务器模式）")
        # 为客户端列表添加最小高度约束
        self.client_list_frame.configure(height=150)
        self.client_list_frame.pack_propagate(False)  # 防止框架大小被内容撑开
        
        # 客户端列表标题栏（展开/折叠 + 状态提示）
        client_header = ttk.Frame(self.client_list_frame)
        client_header.pack(fill=tk.X, padx=5, pady=2)
        
        # 展开/折叠按钮
        self.expand_btn = ttk.Button(
            client_header, text="▼", width=2, command=self.toggle_client_list
        )
        self.expand_btn.pack(side=tk.LEFT, padx=5)
        
        # 客户端状态提示（实时显示：选中的IP + 在线数量）
        self.client_status_label = ttk.Label(
            client_header, text="当前选中: 无 (在线客户端: 0)"
        )
        self.client_status_label.pack(side=tk.LEFT, padx=5)
        
        # 断开当前客户端按钮
        self.disconnect_btn = ttk.Button(
            client_header, text="断开当前", command=self.disconnect_selected_client
        )
        self.disconnect_btn.pack(side=tk.RIGHT, padx=5)
        
        # 客户端列表内容
        self.clients_pane = ttk.PanedWindow(self.client_list_frame, orient=tk.VERTICAL)
        
        self.clients_container = ttk.Frame(self.clients_pane)
        self.clients_pane.add(self.clients_container, weight=1)
        
        # 客户端列表框（显示IP:端口）
        self.clients_listbox = tk.Listbox(
            self.clients_container, width=60, height=5, font=("SimHei", 10)
        )
        self.clients_listbox.bind('<<ListboxSelect>>', self.on_client_select)  # 选中事件
        self.clients_listbox.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5, pady=2)
        
        # 列表滚动条
        client_scroll = ttk.Scrollbar(
            self.clients_container, orient="vertical", command=self.clients_listbox.yview
        )
        client_scroll.pack(side=tk.RIGHT, fill=tk.Y, pady=2)
        self.clients_listbox.config(yscrollcommand=client_scroll.set)
        
        # 3.4 发送按钮栏
        send_btn_frame = ttk.Frame(self.send_frame)
        send_btn_frame.pack(fill=tk.X)
        
        # 加载文件按钮
        ttk.Button(
            send_btn_frame, text="加载文件", command=self.load_file
        ).pack(side=tk.RIGHT, padx=5)
        
        # 发送按钮
        ttk.Button(
            send_btn_frame, text="发送", command=self.send_data
        ).pack(side=tk.RIGHT, padx=5)
        
        # ---------------------- 右侧选项卡区域（自动应答/快捷指令） ----------------------
        right_frame = ttk.Frame(main_paned)
        main_paned.add(right_frame, weight=1)
        
        # 创建选项卡控件
        self.right_notebook = ttk.Notebook(right_frame)
        self.right_notebook.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 1. 自动应答选项卡
        self.response_tab = ttk.Frame(self.right_notebook)
        self.right_notebook.add(self.response_tab, text="自动应答")
        
        # 自动应答控制栏
        response_ctrl = ttk.Frame(self.response_tab)
        response_ctrl.pack(fill=tk.X, pady=(10, 10), padx=10)
        
        # 总开关
        ttk.Checkbutton(
            response_ctrl, text="启用自动应答", variable=self.auto_response_enabled
        ).pack(side=tk.LEFT)
        
        # 规则操作按钮（添加/删除/清空）
        btn_group = ttk.Frame(response_ctrl)
        btn_group.pack(side=tk.RIGHT)
        ttk.Button(btn_group, text="添加行", command=self.add_response_rule, width=8).pack(side=tk.RIGHT, padx=2)
        ttk.Button(btn_group, text="删除选中", command=self.delete_selected_rules, width=8).pack(side=tk.RIGHT, padx=2)
        ttk.Button(btn_group, text="清空所有", command=self.clear_all_rules, width=8).pack(side=tk.RIGHT, padx=2)
        
        # 规则列表标题
        rule_header = ttk.Frame(self.response_tab)
        rule_header.pack(fill=tk.X, padx=10)
        header_labels = ["全选", "启用", "优先级", "指令匹配", "Hex", "指令应答", "Hex", "备注"]
        header_widths = [30, 30, 50, 180, 30, 180, 30, 100]
        for i, (label, width) in enumerate(zip(header_labels, header_widths)):
            if label == "全选":
                ttk.Checkbutton(
                    rule_header, variable=self.select_all_var, command=self.toggle_select_all
                ).grid(row=0, column=i, padx=2, pady=2, sticky="nsew")
            else:
                ttk.Label(rule_header, text=label).grid(row=0, column=i, padx=2, pady=2, sticky="nsew")
            rule_header.grid_columnconfigure(i, minsize=width)
        
        # 规则列表容器（带滚动条）
        rule_scroll_frame = ttk.Frame(self.response_tab)
        rule_scroll_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        rule_canvas = tk.Canvas(rule_scroll_frame)
        rule_scrollbar = ttk.Scrollbar(
            rule_scroll_frame, orient="vertical", command=rule_canvas.yview
        )
        self.rules_frame = ttk.Frame(rule_canvas)  # 规则内容框架
        
        # 绑定滚动事件
        self.rules_frame.bind(
            "<Configure>",
            lambda e: rule_canvas.configure(scrollregion=rule_canvas.bbox("all"))
        )
        
        rule_canvas.create_window((0, 0), window=self.rules_frame, anchor="nw")
        rule_canvas.configure(yscrollcommand=rule_scrollbar.set)
        
        rule_canvas.pack(side="left", fill="both", expand=True)
        rule_scrollbar.pack(side="right", fill="y")
        
        # 设置规则框架列宽
        for i, width in enumerate(header_widths):
            self.rules_frame.grid_columnconfigure(i, minsize=width)
        
        # 2. 快捷指令选项卡
        self.shortcut_tab = ttk.Frame(self.right_notebook)
        self.right_notebook.add(self.shortcut_tab, text="快捷指令")
        
        # 快捷指令控制栏
        shortcut_ctrl = ttk.Frame(self.shortcut_tab)
        shortcut_ctrl.pack(fill=tk.X, pady=(10, 10), padx=10)
        
        # 快捷指令操作按钮（添加/删除/清空）
        shortcut_btn_group = ttk.Frame(shortcut_ctrl)
        shortcut_btn_group.pack(side=tk.RIGHT)
        ttk.Button(shortcut_btn_group, text="添加指令", command=self.add_shortcut_command, width=8).pack(side=tk.RIGHT, padx=2)
        ttk.Button(shortcut_btn_group, text="删除选中", command=self.delete_selected_shortcuts, width=8).pack(side=tk.RIGHT, padx=2)
        ttk.Button(shortcut_btn_group, text="清空所有", command=self.clear_all_shortcuts, width=8).pack(side=tk.RIGHT, padx=2)
        
        # 快捷指令列表标题
        shortcut_header = ttk.Frame(self.shortcut_tab)
        shortcut_header.pack(fill=tk.X, padx=10)
        shortcut_labels = ["全选", "启用", "指令名称", "指令内容", "Hex", "操作"]
        shortcut_widths = [30, 30, 100, 300, 30, 80]
        for i, (label, width) in enumerate(zip(shortcut_labels, shortcut_widths)):
            if label == "全选":
                ttk.Checkbutton(
                    shortcut_header, variable=self.shortcut_select_all_var, command=self.toggle_shortcut_select_all
                ).grid(row=0, column=i, padx=2, pady=2, sticky="nsew")
            else:
                ttk.Label(shortcut_header, text=label).grid(row=0, column=i, padx=2, pady=2, sticky="nsew")
            shortcut_header.grid_columnconfigure(i, minsize=width)
        
        # 快捷指令列表容器（带滚动条）
        shortcut_scroll_frame = ttk.Frame(self.shortcut_tab)
        shortcut_scroll_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        shortcut_canvas = tk.Canvas(shortcut_scroll_frame)
        shortcut_scrollbar = ttk.Scrollbar(
            shortcut_scroll_frame, orient="vertical", command=shortcut_canvas.yview
        )
        self.shortcuts_frame = ttk.Frame(shortcut_canvas)  # 快捷指令内容框架
        
        # 绑定滚动事件
        self.shortcuts_frame.bind(
            "<Configure>",
            lambda e: shortcut_canvas.configure(scrollregion=shortcut_canvas.bbox("all"))
        )
        
        shortcut_canvas.create_window((0, 0), window=self.shortcuts_frame, anchor="nw")
        shortcut_canvas.configure(yscrollcommand=shortcut_scrollbar.set)
        
        shortcut_canvas.pack(side="left", fill="both", expand=True)
        shortcut_scrollbar.pack(side="right", fill="y")
        
        # 设置快捷指令框架列宽
        for i, width in enumerate(shortcut_widths):
            self.shortcuts_frame.grid_columnconfigure(i, minsize=width)
    
    # ---------------------- 快捷指令管理 ----------------------
    def update_shortcut_commands_ui(self):
        """更新快捷指令列表UI"""
        # 清除现有指令控件
        for widget in self.shortcuts_frame.winfo_children():
            widget.destroy()
        
        # 重置变量列表
        self.shortcut_vars = []
        
        # 显示所有快捷指令
        for i, cmd in enumerate(self.shortcut_commands):
            # 为每一行创建独立变量容器
            row_vars = {}
            
            # 1. 选择复选框
            select_var = tk.BooleanVar(value=cmd["selected"])
            select_check = ttk.Checkbutton(self.shortcuts_frame, variable=select_var)
            
            def update_selected(idx, var):
                self.shortcut_commands[idx]["selected"] = var.get()
                all_selected = all(c["selected"] for c in self.shortcut_commands)
                self.shortcut_select_all_var.set(all_selected)
            
            select_check.config(command=lambda idx=i, var=select_var: update_selected(idx, var))
            select_check.grid(row=i, column=0, padx=2, pady=1, sticky="nsew")
            row_vars['select'] = select_var
            
            # 2. 启用复选框
            enabled_var = tk.BooleanVar(value=cmd["enabled"])
            enabled_check = ttk.Checkbutton(
                self.shortcuts_frame, variable=enabled_var,
                command=lambda idx=i, var=enabled_var: self.update_shortcut(idx, "enabled", var.get())
            )
            enabled_check.grid(row=i, column=1, padx=2, pady=1, sticky="nsew")
            row_vars['enabled'] = enabled_var
            
            # 3. 指令名称输入框
            name_var = tk.StringVar(value=cmd["name"])
            name_entry = ttk.Entry(self.shortcuts_frame, textvariable=name_var, width=10)
            name_entry.bind(
                "<FocusOut>",
                lambda e, idx=i, var=name_var: self.update_shortcut(idx, "name", var.get())
            )
            name_entry.grid(row=i, column=2, padx=2, pady=1, sticky="ew")
            row_vars['name'] = name_var
            
            # 4. 指令内容输入框
            content_var = tk.StringVar(value=cmd["content"])
            content_entry = ttk.Entry(self.shortcuts_frame, textvariable=content_var, width=30)
            content_entry.bind(
                "<FocusOut>",
                lambda e, idx=i, var=content_var: self.update_shortcut(idx, "content", var.get())
            )
            content_entry.grid(row=i, column=3, padx=2, pady=1, sticky="ew")
            row_vars['content'] = content_var
            
            # 5. Hex模式复选框
            is_hex_var = tk.BooleanVar(value=cmd["is_hex"])
            is_hex_check = ttk.Checkbutton(
                self.shortcuts_frame, variable=is_hex_var,
                command=lambda idx=i, var=is_hex_var: self.update_shortcut_hex_mode(idx, var.get())
            )
            is_hex_check.grid(row=i, column=4, padx=2, pady=1, sticky="nsew")
            row_vars['is_hex'] = is_hex_var
            
            # 6. 发送按钮
            send_btn = ttk.Button(
                self.shortcuts_frame, text="发送", 
                command=lambda idx=i: self.send_shortcut_command(idx)
            )
            send_btn.grid(row=i, column=5, padx=2, pady=1, sticky="nsew")
            
            # 保存当前行变量
            self.shortcut_vars.append(row_vars)
    
    def update_shortcut(self, index, field, value):
        """更新快捷指令字段值"""
        if 0 <= index < len(self.shortcut_commands) and field in self.shortcut_commands[index]:
            self.shortcut_commands[index][field] = value
    
    def update_shortcut_hex_mode(self, index, is_hex):
        """更新快捷指令的Hex模式并转换内容"""
        if not (0 <= index < len(self.shortcut_commands)):
            return
            
        cmd = self.shortcut_commands[index]
        current_content = cmd["content"].strip()
        
        # 只有当内容不为空时才进行转换
        if current_content:
            # 保存原始内容到临时变量，用于转换
            if not cmd.get("temp_buffer"):
                cmd["temp_buffer"] = current_content
            
            try:
                if is_hex:
                    # 切换到Hex模式：将文本转换为十六进制
                    if cmd["temp_buffer"] and not current_content.startswith("0x"):
                        hex_str = cmd["temp_buffer"].encode('utf-8').hex(' ')
                        cmd["content"] = hex_str
                else:
                    # 切换到文本模式：将十六进制转换为文本
                    if current_content:
                        try:
                            # 清理十六进制字符串
                            hex_clean = current_content.replace(" ", "")
                            if hex_clean:
                                text_str = bytes.fromhex(hex_clean).decode('utf-8', errors='replace')
                                cmd["content"] = text_str
                        except:
                            # 转换失败时保留原始内容
                            pass
                    # 恢复临时缓存
                    cmd["content"] = cmd["temp_buffer"]
            except Exception as e:
                self.log_message(f"快捷指令格式转换错误: {str(e)}", is_error=True)
        
        # 更新Hex标记（无论内容是否为空都更新状态）
        cmd["is_hex"] = is_hex
        # 刷新UI
        self.update_shortcut_commands_ui()
    
    def toggle_shortcut_select_all(self):
        """全选/取消全选所有快捷指令"""
        select_all = self.shortcut_select_all_var.get()
        for cmd in self.shortcut_commands:
            cmd["selected"] = select_all
        self.update_shortcut_commands_ui()
    
    def add_shortcut_command(self):
        """添加新的快捷指令行"""
        # 自动生成指令名称
        cmd_count = len(self.shortcut_commands) + 1
        self.shortcut_commands.append({
            "name": f"指令{cmd_count}", "content": "", "is_hex": False,
            "enabled": True, "selected": False, "temp_buffer": ""
        })
        self.update_shortcut_commands_ui()
    
    def delete_selected_shortcuts(self):
        """删除选中的快捷指令"""
        to_delete = [i for i, c in enumerate(self.shortcut_commands) if c["selected"]]
        if not to_delete:
            messagebox.showinfo("提示", "请先勾选要删除的指令")
            return
            
        if messagebox.askyesno("确认", f"确定删除选中的 {len(to_delete)} 条指令?"):
            # 从后往前删除，避免索引错乱
            for i in sorted(to_delete, reverse=True):
                del self.shortcut_commands[i]
            
            self.update_shortcut_commands_ui()
    
    def clear_all_shortcuts(self):
        """清空所有快捷指令"""
        if not self.shortcut_commands:
            return
            
        if messagebox.askyesno("确认", "确定清空所有快捷指令?"):
            self.shortcut_commands = []
            self.add_shortcut_command()  # 至少保留一行空指令
            self.update_shortcut_commands_ui()
    
    def send_shortcut_command(self, index):
        """发送指定的快捷指令"""
        if not self.running or not self.socket:
            self.log_message("未启动，无法发送数据", is_error=True)
            return
            
        if not (0 <= index < len(self.shortcut_commands)):
            return
            
        cmd = self.shortcut_commands[index]
        if not cmd["enabled"]:
            self.log_message(f"快捷指令 '{cmd['name']}' 已禁用", is_error=True)
            return
            
        content = cmd["content"].strip()
        if not content:
            self.log_message(f"快捷指令 '{cmd['name']}' 内容为空", is_error=True)
            return
        
        try:
            # 处理十六进制发送
            if cmd["is_hex"]:
                data_clean = content.replace(" ", "")
                send_bytes = bytes.fromhex(data_clean)
            else:
                send_bytes = content.encode("utf-8")
                if self.append_newline_var.get():
                    send_bytes += b"\r\n"  # 添加换行符
            
            # 确定发送目标（与普通发送逻辑一致）
            if self.protocol_var.get() == "TCP" and self.mode_var.get() == "服务器":
                # TCP服务器：发送给选中的客户端
                if self.selected_client_idx == -1:
                    # 选中"所有客户端"时提示使用广播
                    messagebox.showinfo("提示", "请选择单个客户端或使用'广播到所有'")
                    return
                elif 0 <= self.selected_client_idx < len(self.connections):
                    target_conn = self.connections[self.selected_client_idx]["connection"]
                    target_conn.sendall(send_bytes)
                else:
                    self.log_message("选中的客户端不存在", is_error=True)
                    return
            elif self.protocol_var.get() == "TCP" and self.mode_var.get() == "客户端":
                # TCP客户端：发送给服务器
                self.socket.sendall(send_bytes)
            else:
                # UDP：发送到指定远程地址
                remote_ip = self.remote_ip_var.get()
                remote_port = int(self.remote_port_var.get())
                self.socket.sendto(send_bytes, (remote_ip, remote_port))
            
            # 记录发送数据
            self.received_data_history.append({
                "data": send_bytes,
                "timestamp": datetime.now(),
                "is_received": False,
                "is_sent": True,
                "addr": None,
                "is_error": False,
                "is_debug": False,
                "message": f"[快捷指令: {cmd['name']}]"
            })
            
            # 刷新显示
            self.refresh_display()
            
        except Exception as e:
            self.log_message(f"发送快捷指令错误: {str(e)}", is_error=True)
    
    # ---------------------- 客户端列表管理 ----------------------
    def toggle_client_list(self):
        """切换客户端列表的展开/折叠状态"""
        self.clients_expanded = not self.clients_expanded
        
        if self.clients_expanded:
            # 展开列表并刷新内容
            self.clients_pane.pack(fill=tk.BOTH, expand=True, padx=5, pady=2)
            self.expand_btn.config(text="▲")
            self.update_clients_list()
            # 调整发送区域高度以适应展开的列表
            self.send_frame.update_idletasks()
            self.send_frame.configure(height=self.send_frame.winfo_height())
        else:
            # 折叠列表
            self.clients_pane.pack_forget()
            self.expand_btn.config(text="▼")
            # 调整发送区域高度
            self.send_frame.update_idletasks()
            self.send_frame.configure(height=self.send_frame.winfo_height())
    
    def update_clients_list(self):
        """更新客户端列表内容（显示所有客户端IP:端口）"""
        # 清空现有列表
        self.clients_listbox.delete(0, tk.END)
        
        # 添加"所有客户端"选项
        self.clients_listbox.insert(tk.END, f"所有客户端 ({len(self.connections)})")
        
        # 添加每个客户端的IP:端口
        for conn in self.connections:
            addr = conn["address"]
            self.clients_listbox.insert(tk.END, f"{addr[0]}:{addr[1]}")
        
        # 保持选中状态
        if self.selected_client_idx == -1:
            self.clients_listbox.selection_set(0)  # 选中"所有客户端"
        elif 0 <= self.selected_client_idx < len(self.connections):
            self.clients_listbox.selection_set(self.selected_client_idx + 1)  # +1是因为第0项是"所有客户端"
        
        # 更新状态标签
        self.update_client_status_label()
    
    def update_client_status_label(self):
        """更新客户端状态标签（显示选中的IP和在线数量）"""
        client_count = len(self.connections)
        if self.selected_client_idx == -1:
            status_text = f"当前选中: 所有客户端 (在线客户端: {client_count})"
        elif 0 <= self.selected_client_idx < len(self.connections):
            addr = self.connections[self.selected_client_idx]["address"]
            status_text = f"当前选中: {addr[0]}:{addr[1]} (在线客户端: {client_count})"
        else:
            status_text = f"当前选中: 无效 (在线客户端: {client_count})"
        
        self.client_status_label.config(text=status_text)
    
    def on_client_select(self, event):
        """处理客户端选择事件（更新选中的IP）"""
        selected = self.clients_listbox.curselection()
        if not selected:
            return
            
        index = selected[0]
        if index == 0:  # 选择"所有客户端"
            self.selected_client_idx = -1
            self.main_connection = None
        else:  # 选择具体客户端
            client_index = index - 1  # 减去"所有客户端"选项
            if 0 <= client_index < len(self.connections):
                self.selected_client_idx = client_index
                self.main_connection = self.connections[client_index]["connection"]
        
        # 更新状态标签
        self.update_client_status_label()
    
    def disconnect_selected_client(self):
        """断开选中的客户端连接"""
        if not self.connections:
            messagebox.showinfo("提示", "没有在线客户端")
            return
            
        if self.selected_client_idx == -1:  # 断开所有客户端
            if messagebox.askyesno("确认", f"确定断开所有 {len(self.connections)} 个客户端?"):
                # 复制连接列表避免迭代中修改
                connections_copy = self.connections.copy()
                for conn in connections_copy:
                    self.disconnect_client(conn)
                
                # 重置选择
                self.selected_client_idx = -1
                self.main_connection = None
        else:  # 断开单个客户端
            if 0 <= self.selected_client_idx < len(self.connections):
                conn = self.connections[self.selected_client_idx]
                addr = conn["address"]
                if messagebox.askyesno("确认", f"确定断开 {addr[0]}:{addr[1]}?"):
                    self.disconnect_client(conn)
                    # 重置选择为"所有客户端"
                    self.selected_client_idx = -1
                    self.main_connection = None
        
        # 更新列表和状态
        self.update_clients_list()
        self.update_client_status_label()
    
    def disconnect_client(self, conn):
        """断开单个客户端连接"""
        try:
            addr = conn["address"]
            if conn["connection"]:
                conn["connection"].shutdown(socket.SHUT_RDWR)
                conn["connection"].close()
            
            if conn in self.connections:
                self.connections.remove(conn)
            
            self.log_message(f"已断开与 {addr[0]}:{addr[1]} 的连接")
        except Exception as e:
            self.log_message(f"断开连接错误: {str(e)}", is_error=True)
    
    # ---------------------- UI更新与初始化 ----------------------
    def update_ui(self):
        """根据协议和模式更新UI元素可见性"""
        protocol = self.protocol_var.get()
        mode = self.mode_var.get()
        
        # 重置所有控件显示状态
        for widget in [self.mode_label, self.mode_frame,
                      self.local_ip_label, self.local_ip_entry,
                      self.local_port_label, self.local_port_entry,
                      self.remote_ip_label, self.remote_ip_entry,
                      self.remote_port_label, self.remote_port_entry,
                      self.client_list_frame, self.broadcast_btn]:
            try:
                widget.pack_forget()
            except:
                pass
        
        # 更新控制按钮文本
        if protocol == "TCP":
            self.control_btn.config(text="连接" if mode == "客户端" else "启动")
            self.mode_label.pack(side=tk.LEFT, padx=(0, 5))
            self.mode_frame.pack(side=tk.LEFT, padx=(0, 20))
            
            if mode == "客户端":
                # TCP客户端：显示远程IP和端口
                self.remote_ip_label.pack(side=tk.LEFT, padx=(0, 5), pady=5)
                self.remote_ip_entry.pack(side=tk.LEFT, padx=(0, 15), pady=5)
                self.remote_port_label.pack(side=tk.LEFT, padx=(0, 5), pady=5)
                self.remote_port_entry.pack(side=tk.LEFT, padx=(0, 15), pady=5)
                
                # 隐藏客户端列表（TCP客户端无多个连接）
                self.client_list_frame.pack_forget()
            else:  # TCP服务器
                # 显示本地IP和监听端口（复用remote_port输入框）
                self.local_ip_label.pack(side=tk.LEFT, padx=(0, 5), pady=5)
                self.local_ip_entry.pack(side=tk.LEFT, padx=(0, 15), pady=5)
                self.remote_port_label.pack(side=tk.LEFT, padx=(0, 5), pady=5)
                self.remote_port_entry.pack(side=tk.LEFT, padx=(0, 15), pady=5)
                
                # 显示客户端列表和广播按钮
                self.client_list_frame.pack(fill=tk.X, pady=(0, 5))
                self.broadcast_btn.pack(side=tk.LEFT, padx=5)
                # 确保列表区域可见
                if self.clients_expanded:
                    self.clients_pane.pack(fill=tk.BOTH, expand=True, padx=5, pady=2)
        else:  # UDP模式
            self.control_btn.config(text="启动")
            # 隐藏模式选择和客户端列表（UDP无连接概念）
            self.mode_label.pack_forget()
            self.mode_frame.pack_forget()
            self.client_list_frame.pack_forget()
            
            # 显示本地和远程IP/端口
            self.local_ip_label.pack(side=tk.LEFT, padx=(0, 5), pady=5)
            self.local_ip_entry.pack(side=tk.LEFT, padx=(0, 15), pady=5)
            self.local_port_label.pack(side=tk.LEFT, padx=(0, 5), pady=5)
            self.local_port_entry.pack(side=tk.LEFT, padx=(0, 15), pady=5)
            
            self.remote_ip_label.pack(side=tk.LEFT, padx=(0, 5), pady=5)
            self.remote_ip_entry.pack(side=tk.LEFT, padx=(0, 15), pady=5)
            self.remote_port_label.pack(side=tk.LEFT, padx=(0, 5), pady=5)
            self.remote_port_entry.pack(side=tk.LEFT, padx=(0, 15), pady=5)
        
        # 重新布局发送区域控件
        send_ctrl = self.send_entry.master.winfo_children()[0]
        send_ctrl.pack(fill=tk.X, pady=(0, 5))
        self.send_entry.pack(fill=tk.BOTH, expand=True, pady=(0, 5))
        
        # 发送按钮栏重新布局
        send_btn_frame = self.send_entry.master.winfo_children()[-1]
        send_btn_frame.pack(fill=tk.X)
        
        # 强制刷新布局，确保所有元素正确显示
        self.root.update_idletasks()
    
    # ---------------------- 自动应答规则管理 ----------------------
    def update_response_rules_ui(self):
        """更新自动应答规则列表UI"""
        # 清除现有规则控件
        for widget in self.rules_frame.winfo_children():
            widget.destroy()
        
        # 重置变量列表
        self.rule_vars = []
        
        # 按优先级排序规则
        sorted_rules = sorted(self.auto_responses, key=lambda x: x["priority"])
        
        # 添加所有规则行
        for i, rule in enumerate(sorted_rules):
            # 为每一行创建独立变量容器
            row_vars = {}
            
            # 1. 选择复选框
            select_var = tk.BooleanVar(value=rule["selected"])
            select_check = ttk.Checkbutton(self.rules_frame, variable=select_var)
            
            def update_selected(idx, var):
                sorted_rules[idx]["selected"] = var.get()
                all_selected = all(r["selected"] for r in sorted_rules)
                self.select_all_var.set(all_selected)
            
            select_check.config(command=lambda idx=i, var=select_var: update_selected(idx, var))
            select_check.grid(row=i, column=0, padx=2, pady=1, sticky="nsew")
            row_vars['select'] = select_var
            
            # 2. 启用复选框
            enabled_var = tk.BooleanVar(value=rule["enabled"])
            enabled_check = ttk.Checkbutton(
                self.rules_frame, variable=enabled_var,
                command=lambda idx=i, var=enabled_var: self.update_rule(idx, "enabled", var.get())
            )
            enabled_check.grid(row=i, column=1, padx=2, pady=1, sticky="nsew")
            row_vars['enabled'] = enabled_var
            
            # 3. 优先级输入框
            priority_var = tk.StringVar(value=str(rule["priority"]))
            priority_entry = ttk.Entry(self.rules_frame, textvariable=priority_var, width=5)
            priority_entry.bind(
                "<FocusOut>",
                lambda e, idx=i, var=priority_var: self.update_rule(idx, "priority", var.get())
            )
            priority_entry.grid(row=i, column=2, padx=2, pady=1, sticky="nsew")
            row_vars['priority'] = priority_var
            
            # 4. 指令匹配输入框
            pattern_var = tk.StringVar(value=rule["pattern"])
            pattern_entry = ttk.Entry(self.rules_frame, textvariable=pattern_var)
            pattern_entry.bind(
                "<FocusOut>",
                lambda e, idx=i, var=pattern_var: self.update_rule(idx, "pattern", var.get())
            )
            pattern_entry.grid(row=i, column=3, padx=2, pady=1, sticky="ew")
            row_vars['pattern'] = pattern_var
            
            # 5. 指令匹配Hex复选框
            pattern_hex_var = tk.BooleanVar(value=rule["pattern_is_hex"])
            pattern_hex_check = ttk.Checkbutton(
                self.rules_frame, variable=pattern_hex_var,
                command=lambda idx=i, var=pattern_hex_var: self.update_rule_hex_mode(idx, "pattern", var.get())
            )
            pattern_hex_check.grid(row=i, column=4, padx=2, pady=1, sticky="nsew")
            row_vars['pattern_hex'] = pattern_hex_var
            
            # 6. 指令应答输入框
            response_var = tk.StringVar(value=rule["response"])
            response_entry = ttk.Entry(self.rules_frame, textvariable=response_var)
            response_entry.bind(
                "<FocusOut>",
                lambda e, idx=i, var=response_var: self.update_rule(idx, "response", var.get())
            )
            response_entry.grid(row=i, column=5, padx=2, pady=1, sticky="ew")
            row_vars['response'] = response_var
            
            # 7. 指令应答Hex复选框
            response_hex_var = tk.BooleanVar(value=rule["response_is_hex"])
            response_hex_check = ttk.Checkbutton(
                self.rules_frame, variable=response_hex_var,
                command=lambda idx=i, var=response_hex_var: self.update_rule_hex_mode(idx, "response", var.get())
            )
            response_hex_check.grid(row=i, column=6, padx=2, pady=1, sticky="nsew")
            row_vars['response_hex'] = response_hex_var
            
            # 8. 备注输入框
            remark_var = tk.StringVar(value=rule["remark"])
            remark_entry = ttk.Entry(self.rules_frame, textvariable=remark_var)
            remark_entry.bind(
                "<FocusOut>",
                lambda e, idx=i, var=remark_var: self.update_rule(idx, "remark", var.get())
            )
            remark_entry.grid(row=i, column=7, padx=2, pady=1, sticky="ew")
            row_vars['remark'] = remark_var
            
            # 保存当前行变量
            self.rule_vars.append(row_vars)
    
    def update_rule(self, index, field, value):
        """更新自动应答规则字段值"""
        if 0 <= index < len(self.auto_responses) and field in self.auto_responses[index]:
            # 处理优先级（确保为整数）
            if field == "priority":
                try:
                    self.auto_responses[index][field] = int(value)
                except ValueError:
                    self.auto_responses[index][field] = 1
                    self.update_response_rules_ui()  # 重新刷新UI
            else:
                self.auto_responses[index][field] = value
    
    def update_rule_hex_mode(self, index, field, is_hex):
        """更新自动应答规则的Hex模式并转换内容
           当勾选Hex时，如果框内有数据则转换为Hex形式
           当取消勾选时，保持原有内容不变
        """
        if not (0 <= index < len(self.auto_responses)) or field not in ["pattern", "response"]:
            return
            
        rule = self.auto_responses[index]
        content_field = field
        hex_field = f"{field}_is_hex"
        buffer_field = f"{field}_buffer"
        
        # 获取当前内容
        current_content = rule[content_field].strip()
        
        # 只有当内容不为空时才进行转换
        if current_content:
            # 保存原始内容到缓冲区（只在首次转换时保存）
            if not rule.get(buffer_field):
                rule[buffer_field] = current_content
            
            try:
                if is_hex:
                    # 切换到Hex模式：将文本转换为十六进制
                    # 检查是否已经是十六进制格式
                    if not (current_content.startswith("0x") or all(c in "0123456789ABCDEFabcdef " for c in current_content)):
                        hex_str = rule[buffer_field].encode('utf-8').hex(' ')
                        rule[content_field] = hex_str
                # 取消勾选时不做转换，保持当前内容
            except Exception as e:
                self.log_message(f"自动应答规则格式转换错误: {str(e)}", is_error=True)
        
        # 更新Hex标记（无论内容是否为空都更新状态）
        rule[hex_field] = is_hex
        # 刷新UI
        self.update_response_rules_ui()
    
    def toggle_select_all(self):
        """全选/取消全选所有规则"""
        select_all = self.select_all_var.get()
        for rule in self.auto_responses:
            rule["selected"] = select_all
        self.update_response_rules_ui()
    
    def add_response_rule(self):
        """添加新的自动应答规则行"""
        # 自动分配优先级（最大值+1）
        max_priority = max((r["priority"] for r in self.auto_responses), default=0)
        self.auto_responses.append({
            "priority": max_priority + 1, "pattern": "", "pattern_is_hex": False,
            "response": "", "response_is_hex": False, "remark": "",
            "enabled": True, "selected": False,
            "pattern_buffer": "", "response_buffer": ""
        })
        self.update_response_rules_ui()
    
    def delete_selected_rules(self):
        """删除选中的规则行"""
        to_delete = [i for i, r in enumerate(self.auto_responses) if r["selected"]]
        if not to_delete:
            messagebox.showinfo("提示", "请先勾选要删除的规则")
            return
            
        if messagebox.askyesno("确认", f"确定删除选中的 {len(to_delete)} 条规则?"):
            # 从后往前删除，避免索引错乱
            for i in sorted(to_delete, reverse=True):
                del self.auto_responses[i]
            
            # 重新排序优先级
            for i, rule in enumerate(sorted(self.auto_responses, key=lambda x: x["priority"])):
                rule["priority"] = i + 1
                
            self.update_response_rules_ui()
    
    def clear_all_rules(self):
        """清空所有自动应答规则"""
        if not self.auto_responses:
            return
            
        if messagebox.askyesno("确认", "确定清空所有规则?"):
            self.auto_responses = []
            self.add_response_rule()  # 至少保留一行空规则
            self.update_response_rules_ui()
    
    # ---------------------- 网络核心功能 ----------------------
    def toggle_connection(self):
        """切换连接状态（启动/停止）"""
        if self.running:
            self.stop()
        else:
            self.start()
    
    def start(self):
        """启动网络（TCP客户端/服务器或UDP）"""
        try:
            protocol = self.protocol_var.get()
            
            # 重置状态
            self.socket = None
            self.connections = []
            self.main_connection = None
            self.selected_client_idx = -1
            self.update_client_status_label()
            
            if protocol == "TCP":
                self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 允许端口重用
                
                if self.mode_var.get() == "服务器":
                    # TCP服务器：监听指定端口（使用remote_port输入框）
                    local_ip = self.local_ip_var.get() or "0.0.0.0"
                    try:
                        listen_port = int(self.remote_port_var.get())
                        if not (1 <= listen_port <= 65535):
                            raise ValueError("端口必须在1-65535之间")
                    except ValueError as e:
                        self.log_message(f"端口错误: {str(e)}", is_error=True)
                        return
                    
                    self.socket.bind((local_ip, listen_port))
                    self.socket.listen(5)  # 最大等待连接数
                    
                    # 显示实际监听地址
                    actual_ip, actual_port = self.socket.getsockname()
                    self.log_message(f"TCP服务器已启动，监听 {actual_ip}:{actual_port}")
                    self.status_var.set(f"TCP服务器: 监听 {actual_ip}:{actual_port}")
                    self.status_label.config(foreground="green")
                    
                    # 启动接受连接的线程
                    self.accept_thread = threading.Thread(
                        target=self.accept_tcp_connections, daemon=True
                    )
                    self.accept_thread.start()
                    
                    # 刷新客户端列表
                    self.root.after(100, self.update_clients_list)
                else:
                    # TCP客户端：连接到远程服务器
                    remote_ip = self.remote_ip_var.get()
                    try:
                        remote_port = int(self.remote_port_var.get())
                        if not (1 <= remote_port <= 65535):
                            raise ValueError("端口必须在1-65535之间")
                    except ValueError as e:
                        self.log_message(f"端口错误: {str(e)}", is_error=True)
                        return
                    
                    self.log_message(f"正在连接到 {remote_ip}:{remote_port}...")
                    self.socket.connect((remote_ip, remote_port))
                    self.main_connection = self.socket
                    
                    # 显示本地和远程地址
                    local_addr = self.socket.getsockname()
                    self.log_message(f"已连接到 TCP 服务器 {remote_ip}:{remote_port}")
                    self.log_message(f"本地地址: {local_addr[0]}:{local_addr[1]}")
                    self.status_var.set(f"TCP客户端: 已连接 {remote_ip}:{remote_port}")
                    self.status_label.config(foreground="green")
                    
                    # 启动接收线程
                    self.start_receive_thread()
            else:
                # UDP模式：绑定本地端口
                self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
                self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                
                local_ip = self.local_ip_var.get() or "0.0.0.0"
                try:
                    local_port = int(self.local_port_var.get() or 0)
                    if local_port != 0 and not (1 <= local_port <= 65535):
                        raise ValueError("端口必须在1-65535之间")
                except ValueError as e:
                    self.log_message(f"端口错误: {str(e)}", is_error=True)
                    return
                
                self.socket.bind((local_ip, local_port))
                local_addr = self.socket.getsockname()  # 获取实际绑定地址
                self.log_message(f"UDP已启动，绑定 {local_addr[0]}:{local_addr[1]}")
                self.log_message(f"默认发送目标: {self.remote_ip_var.get()}:{self.remote_port_var.get()}")
                self.status_var.set(f"UDP: 绑定 {local_addr[0]}:{local_addr[1]}")
                self.status_label.config(foreground="green")
                
                # 启动接收线程
                self.start_receive_thread()
            
            self.running = True
            # 更新按钮文本
            if protocol == "TCP":
                self.control_btn.config(text="断开" if self.mode_var.get() == "客户端" else "停止")
            else:
                self.control_btn.config(text="停止")
                
            self.save_config()  # 保存当前配置
            
        except Exception as e:
            self.log_message(f"启动失败: {str(e)}", is_error=True)
            self.status_var.set("启动失败")
            self.status_label.config(foreground="red")
            self.socket = None
    
    def accept_tcp_connections(self):
        """TCP服务器：循环接受客户端连接"""
        self.log_debug("开始接受TCP客户端连接...")
        
        while self.running and self.socket:
            try:
                self.socket.settimeout(1.0)  # 设置超时，避免阻塞
                conn, addr = self.socket.accept()
                
                # 配置连接属性
                conn.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)  # 禁用Nagle算法
                conn.setblocking(True)
                
                # 添加到连接列表并启动处理线程
                self.connections.append({
                    "connection": conn,
                    "address": addr,
                    "connect_time": datetime.now().strftime("%H:%M:%S")
                })
                
                # 启动客户端处理线程
                client_thread = threading.Thread(
                    target=self.handle_tcp_client,
                    args=(conn, addr),
                    daemon=True
                )
                client_thread.start()
                
                # 刷新客户端列表和状态
                self.root.after(0, self.update_clients_list)
                self.root.after(0, self.update_client_status_label)
                
                self.log_message(f"新客户端连接: {addr[0]}:{addr[1]}")
                
            except socket.timeout:
                continue  # 超时继续等待
            except Exception as e:
                if self.running:
                    self.log_message(f"接受连接错误: {str(e)}", is_error=True)
                break
        
        self.log_debug("停止接受TCP客户端连接")
    
    def handle_tcp_client(self, conn, addr):
        """处理单个TCP客户端的数据接收"""
        try:
            while self.running and conn in [c["connection"] for c in self.connections]:
                # 设置超时，避免线程阻塞
                conn.settimeout(0.5)
                try:
                    data = conn.recv(4096)
                except socket.timeout:
                    continue
                    
                if not data:  # 客户端断开连接
                    self.log_message(f"客户端 {addr[0]}:{addr[1]} 已断开")
                    break
                    
                # 记录接收数据
                self.received_data_history.append({
                    "data": data,
                    "timestamp": datetime.now(),
                    "is_received": True,
                    "is_sent": False,
                    "addr": addr,
                    "is_error": False,
                    "is_debug": False,
                    "message": ""
                })
                
                # 刷新显示
                self.root.after(0, self.refresh_display)
                
                # 检查自动应答
                self.check_auto_response(data, conn)
                
                time.sleep(0.01)
                
        except Exception as e:
            if self.running and conn in [c["connection"] for c in self.connections]:
                self.log_message(f"与 {addr[0]}:{addr[1]} 通信错误: {str(e)}", is_error=True)
        
        finally:
            # 从连接列表移除并更新UI
            for c in self.connections[:]:
                if c["connection"] == conn:
                    self.disconnect_client(c)
                    self.root.after(0, self.update_clients_list)
                    self.root.after(0, self.update_client_status_label)
                    break
    
    def start_receive_thread(self):
        """启动数据接收线程（TCP客户端/UDP）"""
        if hasattr(self, 'receive_thread') and self.receive_thread and self.receive_thread.is_alive():
            return
            
        self.receive_thread = threading.Thread(target=self.receive_data, daemon=True)
        self.receive_thread.start()
        self.log_debug("接收线程已启动")
    
    def receive_data(self):
        """接收数据（TCP客户端/UDP模式）"""
        self.log_debug("开始接收数据...")
        
        while self.running and self.socket:
            try:
                if self.protocol_var.get() == "TCP" and self.mode_var.get() == "客户端":
                    # TCP客户端接收
                    self.socket.settimeout(0.5)
                    try:
                        data = self.socket.recv(4096)
                    except socket.timeout:
                        continue
                        
                    if not data:  # 服务器断开连接
                        self.log_message("TCP服务器已断开连接")
                        self.stop()
                        break
                        
                    # 记录接收数据
                    self.received_data_history.append({
                        "data": data,
                        "timestamp": datetime.now(),
                        "is_received": True,
                        "is_sent": False,
                        "addr": self.socket.getpeername(),
                        "is_error": False,
                        "is_debug": False,
                        "message": ""
                    })
                    
                    # 刷新显示
                    self.root.after(0, self.refresh_display)
                    
                    # 检查自动应答
                    self.check_auto_response(data, self.socket)
                else:
                    # UDP接收
                    self.socket.settimeout(0.5)
                    try:
                        data, addr = self.socket.recvfrom(4096)
                    except socket.timeout:
                        continue
                        
                    # 记录接收数据
                    self.received_data_history.append({
                        "data": data,
                        "timestamp": datetime.now(),
                        "is_received": True,
                        "is_sent": False,
                        "addr": addr,
                        "is_error": False,
                        "is_debug": False,
                        "message": ""
                    })
                    
                    # 刷新显示
                    self.root.after(0, self.refresh_display)
                    
                    # 检查自动应答
                    self.check_auto_response(data)
                
                time.sleep(0.01)
                
            except Exception as e:
                if self.running:
                    self.log_message(f"接收数据错误: {str(e)}", is_error=True)
                break
        
        self.log_debug("接收线程已停止")
    
    def send_data(self):
        """发送数据到选中的目标"""
        if not self.running or not self.socket:
            self.log_message("未启动，无法发送数据", is_error=True)
            return
        
        # 获取发送内容
        data = self.send_entry.get("1.0", tk.END).rstrip("\n")
        if not data:
            return
        
        try:
            # 处理十六进制发送
            if self.hex_send_var.get():
                data_clean = data.replace(" ", "")
                send_bytes = bytes.fromhex(data_clean)
            else:
                send_bytes = data.encode("utf-8")
                if self.append_newline_var.get():
                    send_bytes += b"\r\n"  # 添加换行符
            
            # 确定发送目标
            if self.protocol_var.get() == "TCP" and self.mode_var.get() == "服务器":
                # TCP服务器：发送给选中的客户端
                if self.selected_client_idx == -1:
                    # 选中"所有客户端"时提示使用广播
                    messagebox.showinfo("提示", "请选择单个客户端或使用'广播到所有'")
                    return
                elif 0 <= self.selected_client_idx < len(self.connections):
                    target_conn = self.connections[self.selected_client_idx]["connection"]
                    target_conn.sendall(send_bytes)
                else:
                    self.log_message("选中的客户端不存在", is_error=True)
                    return
            elif self.protocol_var.get() == "TCP" and self.mode_var.get() == "客户端":
                # TCP客户端：发送给服务器
                self.socket.sendall(send_bytes)
            else:
                # UDP：发送到指定远程地址
                remote_ip = self.remote_ip_var.get()
                remote_port = int(self.remote_port_var.get())
                self.socket.sendto(send_bytes, (remote_ip, remote_port))
            
            # 记录发送数据
            self.received_data_history.append({
                "data": send_bytes,
                "timestamp": datetime.now(),
                "is_received": False,
                "is_sent": True,
                "addr": None,
                "is_error": False,
                "is_debug": False,
                "message": ""
            })
            
            # 刷新显示
            self.refresh_display()
            
        except Exception as e:
            self.log_message(f"发送数据错误: {str(e)}", is_error=True)
    
    def broadcast_data(self):
        """TCP服务器：广播数据到所有客户端"""
        if not self.running or self.protocol_var.get() != "TCP" or self.mode_var.get() != "服务器":
            return
            
        if not self.connections:
            self.log_message("没有在线客户端，无法广播", is_error=True)
            return
        
        # 获取发送内容
        data = self.send_entry.get("1.0", tk.END).rstrip("\n")
        if not data:
            return
        
        try:
            # 处理十六进制发送
            if self.hex_send_var.get():
                data_clean = data.replace(" ", "")
                send_bytes = bytes.fromhex(data_clean)
            else:
                send_bytes = data.encode("utf-8")
                if self.append_newline_var.get():
                    send_bytes += b"\r\n"
            
            # 向所有客户端发送
            success = 0
            fail = 0
            connections_copy = self.connections.copy()  # 复制列表避免迭代中修改
            
            for conn in connections_copy:
                try:
                    conn["connection"].sendall(send_bytes)
                    success += 1
                except Exception as e:
                    fail += 1
                    self.log_message(f"向 {conn['address'][0]}:{conn['address'][1]} 发送失败: {str(e)}", is_error=True)
                    self.disconnect_client(conn)
            
            # 记录广播结果
            self.log_message(f"广播完成: 成功 {success} 个, 失败 {fail} 个")
            
            # 记录发送数据
            self.received_data_history.append({
                "data": send_bytes,
                "timestamp": datetime.now(),
                "is_received": False,
                "is_sent": True,
                "addr": None,
                "is_error": False,
                "is_debug": False,
                "message": f"[广播到 {success} 个客户端]"
            })
            
            # 刷新显示和客户端列表
            self.refresh_display()
            self.update_clients_list()
            
        except Exception as e:
            self.log_message(f"广播错误: {str(e)}", is_error=True)
    
    def check_auto_response(self, data, connection=None):
        """检查是否需要自动应答"""
        if not self.auto_response_enabled.get() or not self.auto_responses:
            return
            
        try:
            # 过滤并排序启用的规则（按优先级）
            enabled_rules = [r for r in self.auto_responses if r["enabled"]]
            sorted_rules = sorted(enabled_rules, key=lambda x: x["priority"])
            
            matched_count = 0  # 记录匹配到的规则数量
            
            # 遍历所有规则（执行所有匹配的规则）
            for rule in sorted_rules:
                pattern = rule["pattern"].strip()
                if not pattern:
                    continue
                    
                # 处理Hex模式匹配
                if rule["pattern_is_hex"]:
                    try:
                        pattern_clean = pattern.replace(" ", "")
                        if not pattern_clean:
                            continue
                            
                        pattern_bytes = bytes.fromhex(pattern_clean)
                        # 精确匹配接收数据的前N个字节
                        if data.startswith(pattern_bytes):
                            matched_count += 1
                            self.log_debug(f"触发自动应答 #{matched_count} (优先级 {rule['priority']}): {rule['remark'] or '匹配十六进制模式'}")
                            self.send_auto_response(rule, connection)
                    except ValueError as e:
                        self.log_debug(f"自动应答规则错误: {str(e)}")
                        continue
                else:
                    # 文本模式匹配 - 改进版本
                    try:
                        # 尝试多种编码解码，提高兼容性
                        decodings = [
                            data.decode("utf-8", errors="replace"),  # UTF-8
                            data.decode("gbk", errors="replace"),   # 中文编码
                            data.decode("latin-1")                  # 原始字节解码
                        ]
                        
                        # 去除所有解码结果中的控制字符和不可见字符
                        cleaned_decodings = []
                        for decoding in decodings:
                            cleaned = ''.join([c for c in decoding if c.isprintable() or c in '\r\n\t'])
                            cleaned_decodings.append(cleaned)
                        
                        # 检查是否有任何一种解码结果包含匹配模式
                        pattern_lower = pattern.lower()  # 转换为小写，实现不区分大小写匹配
                        matched = False
                        
                        for cleaned in cleaned_decodings:
                            if pattern_lower in cleaned.lower():  # 不区分大小写匹配
                                matched = True
                                break
                        
                        if matched:
                            matched_count += 1
                            self.log_debug(f"触发自动应答 #{matched_count} (优先级 {rule['priority']}): {rule['remark'] or '匹配文本模式'}")
                            self.send_auto_response(rule, connection)
                    except Exception as e:
                        self.log_debug(f"文本匹配错误: {str(e)}")
                        continue
            
            if matched_count > 0:
                self.log_debug(f"共触发 {matched_count} 条自动应答规则")
                    
        except Exception as e:
            self.log_message(f"自动应答处理错误: {str(e)}", is_error=True)
    
    def send_auto_response(self, rule, connection=None):
        """发送自动应答数据"""
        try:
            # 准备应答数据
            if rule["response_is_hex"]:
                # 十六进制模式
                response_clean = rule["response"].replace(" ", "")
                if len(response_clean) % 2 != 0:
                    raise ValueError("十六进制数据长度必须为偶数")
                response_bytes = bytes.fromhex(response_clean)
            else:
                # 文本模式
                response_bytes = rule["response"].encode("utf-8")
                if self.append_newline_var.get():
                    response_bytes += b"\r\n"
            
            # 发送应答
            if self.protocol_var.get() == "TCP" and self.mode_var.get() == "服务器" and connection:
                # TCP服务器：向触发规则的客户端发送
                connection.sendall(response_bytes)
            elif self.protocol_var.get() == "TCP" and self.mode_var.get() == "客户端":
                # TCP客户端：向服务器发送
                self.socket.sendall(response_bytes)
            elif self.protocol_var.get() == "UDP":
                # UDP：向发送者回复
                remote_ip = self.remote_ip_var.get()
                remote_port = int(self.remote_port_var.get())
                self.socket.sendto(response_bytes, (remote_ip, remote_port))
            
            # 记录自动发送的数据
            self.received_data_history.append({
                "data": response_bytes,
                "timestamp": datetime.now(),
                "is_received": False,
                "is_sent": True,
                "addr": None,
                "is_error": False,
                "is_debug": False,
                "message": f"[自动应答 (优先级 {rule['priority']})]"
            })
            
            self.refresh_display()
            
        except Exception as e:
            self.log_message(f"自动应答发送错误: {str(e)}", is_error=True)
    
    def stop(self):
        """停止网络连接"""
        self.running = False
        
        # 断开所有客户端连接
        if self.connections:
            connections_copy = self.connections.copy()
            for conn in connections_copy:
                self.disconnect_client(conn)
        
        # 关闭主套接字
        if self.socket:
            try:
                self.socket.close()
            except Exception as e:
                self.log_debug(f"关闭套接字错误: {str(e)}")
            self.socket = None
        
        # 重置状态
        self.main_connection = None
        self.selected_client_idx = -1
        self.update_clients_list()
        self.update_client_status_label()
        
        # 更新UI状态
        if self.protocol_var.get() == "TCP":
            self.control_btn.config(text="连接" if self.mode_var.get() == "客户端" else "启动")
        else:
            self.control_btn.config(text="启动")
            
        self.status_var.set("未启动")
        self.status_label.config(foreground="red")
        self.log_message("已停止")
    
    # ---------------------- 数据显示与日志管理 ----------------------
    def log_message(self, message, is_error=False):
        """记录普通消息"""
        self.received_data_history.append({
            "message": message,
            "timestamp": datetime.now(),
            "is_error": is_error,
            "is_received": False,
            "is_sent": False,
            "is_debug": False,
            "data": None,
            "addr": None
        })
        self.refresh_display()
    
    def log_debug(self, message):
        """记录调试消息（仅在Debug模式显示）"""
        self.received_data_history.append({
            "message": message,
            "timestamp": datetime.now(),
            "is_error": False,
            "is_received": False,
            "is_sent": False,
            "is_debug": True,
            "data": None,
            "addr": None
        })
        self.refresh_display()
    
    def refresh_display(self):
        """刷新数据显示区域"""
        self.display_area.config(state=tk.NORMAL)
        self.display_area.delete("1.0", tk.END)
        
        # 显示所有数据
        for entry in self.received_data_history:
            # 过滤不显示的调试信息
            if entry["is_debug"] and not self.debug_mode_var.get():
                continue
                
            # 构建时间戳
            timestamp = ""
            if self.timestamp_var.get() and entry["timestamp"]:
                timestamp = f"[{entry['timestamp'].strftime('%H:%M:%S.%f')[:-3]}] "
            
            # 构建前缀和标签
            prefix = ""
            tag = ""
            
            if entry["is_error"]:
                prefix = "错误: "
                tag = "error"
            elif entry["is_received"]:
                prefix = "接收: "
                if entry["addr"]:
                    prefix = f"来自 {entry['addr'][0]}:{entry['addr'][1]} 接收: "
                tag = "received"
            elif entry["is_sent"]:
                prefix = "发送: "
                if entry.get("message", "").startswith("[广播"):
                    prefix = f"发送{entry['message']}: "
                elif entry.get("message", "").startswith("[自动应答"):
                    prefix = f"发送{entry['message']}: "
                elif entry.get("message", "").startswith("[快捷指令"):
                    prefix = f"发送{entry['message']}: "
                elif self.protocol_var.get() == "TCP" and self.mode_var.get() == "服务器" and self.selected_client_idx != -1 and self.connections:
                    # 显示发送目标IP
                    if 0 <= self.selected_client_idx < len(self.connections):
                        addr = self.connections[self.selected_client_idx]["address"]
                        prefix = f"发送到 {addr[0]}:{addr[1]}: "
                tag = "sent"
            elif entry["is_debug"]:
                prefix = "调试: "
                tag = "debug"
            
            # 处理显示内容
            content = ""
            if entry["data"] is not None:
                # 二进制数据（根据显示模式转换）
                if self.display_mode_var.get() == "Hex":
                    content = " ".join([f"{b:02X}" for b in entry["data"]])
                else:
                    # 尝试解码为文本
                    try:
                        content = entry["data"].decode("utf-8", errors="replace")
                    except:
                        content = f"(无法解码) {' '.join([f'{b:02X}' for b in entry['data']])}"
            else:
                # 文本消息
                content = entry.get("message", "")
            
            # 插入到显示区域
            self.display_area.insert(tk.END, f"{timestamp}{prefix}{content}\n", tag)
        
        # 滚动到底部
        self.display_area.see(tk.END)
        self.display_area.config(state=tk.DISABLED)
    
    def clear_display(self):
        """清空显示区域和历史记录"""
        self.received_data_history = []
        self.display_area.config(state=tk.NORMAL)
        self.display_area.delete("1.0", tk.END)
        self.display_area.config(state=tk.DISABLED)
    
    def save_log(self):
        """保存日志到文件"""
        if not self.received_data_history:
            messagebox.showinfo("提示", "没有可保存的日志")
            return
        
        file_path = filedialog.asksaveasfilename(
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")],
            title="保存日志"
        )
        
        if file_path:
            try:
                with open(file_path, "w", encoding="utf-8") as f:
                    for entry in self.received_data_history:
                        # 过滤调试信息（按当前设置）
                        if entry["is_debug"] and not self.debug_mode_var.get():
                            continue
                            
                        # 时间戳
                        timestamp = ""
                        if self.timestamp_var.get() and entry["timestamp"]:
                            timestamp = f"[{entry['timestamp'].strftime('%H:%M:%S.%f')[:-3]}] "
                        
                        # 前缀
                        prefix = ""
                        if entry["is_error"]:
                            prefix = "错误: "
                        elif entry["is_received"]:
                            prefix = "接收: "
                            if entry["addr"]:
                                prefix = f"来自 {entry['addr'][0]}:{entry['addr'][1]} 接收: "
                        elif entry["is_sent"]:
                            prefix = "发送: "
                            if entry.get("message", "").startswith("[广播"):
                                prefix = f"发送{entry['message']}: "
                            elif entry.get("message", "").startswith("[快捷指令"):
                                prefix = f"发送{entry['message']}: "
                        elif entry["is_debug"]:
                            prefix = "调试: "
                        
                        # 内容
                        content = ""
                        if entry["data"] is not None:
                            if self.display_mode_var.get() == "Hex":
                                content = " ".join([f"{b:02X}" for b in entry["data"]])
                            else:
                                try:
                                    content = entry["data"].decode("utf-8", errors="replace")
                                except:
                                    content = f"(无法解码) {' '.join([f'{b:02X}' for b in entry['data']])}"
                        else:
                            content = entry.get("message", "")
                        
                        f.write(f"{timestamp}{prefix}{content}\n")
                
                self.log_message(f"日志已保存到 {file_path}")
            except Exception as e:
                self.log_message(f"保存日志错误: {str(e)}", is_error=True)
    
    # ---------------------- 发送框辅助功能 ----------------------
    def toggle_hex_send(self):
        """切换十六进制发送模式（自动转换内容）"""
        current_content = self.send_entry.get("1.0", tk.END).rstrip("\n")
        
        if self.hex_send_var.get():
            # 切换到十六进制：保存原始文本，转换为十六进制
            self.send_buffer = current_content
            if current_content:
                try:
                    hex_str = current_content.encode('utf-8').hex(' ')
                    self.send_entry.delete("1.0", tk.END)
                    self.send_entry.insert(tk.END, hex_str)
                except Exception as e:
                    self.log_message(f"转换为十六进制失败: {str(e)}", is_error=True)
        else:
            # 切换到文本：恢复原始内容
            if self.send_buffer:
                self.send_entry.delete("1.0", tk.END)
                self.send_entry.insert(tk.END, self.send_buffer)
                self.send_buffer = ""
    
    def clear_send_entry(self):
        """清空发送框"""
        self.send_entry.delete("1.0", tk.END)
        self.send_buffer = ""
    
    def load_file(self):
        """从文件加载数据到发送框"""
        file_path = filedialog.askopenfilename(
            filetypes=[("所有文件", "*.*"), ("文本文件", "*.txt"), ("二进制文件", "*.bin")],
            title="选择发送文件"
        )
        
        if file_path:
            try:
                # 尝试以文本方式打开
                with open(file_path, "r", encoding="utf-8") as f:
                    content = f.read()
                    self.send_entry.delete("1.0", tk.END)
                    self.send_entry.insert(tk.END, content)
                    self.send_buffer = content
            except UnicodeDecodeError:
                # 二进制文件处理为十六进制
                with open(file_path, "rb") as f:
                    data = f.read()
                    hex_str = data.hex(' ')
                    self.send_entry.delete("1.0", tk.END)
                    self.send_entry.insert(tk.END, hex_str)
                    self.send_buffer = ""
                    self.hex_send_var.set(True)
            
            self.log_message(f"已加载文件: {file_path}")
    
    # ---------------------- 配置保存与加载 ----------------------
    def save_config(self):
        """保存当前配置到文件"""
        try:
            config = {
                "protocol": self.protocol_var.get(),
                "mode": self.mode_var.get(),
                "local_ip": self.local_ip_var.get(),
                "local_port": self.local_port_var.get(),
                "remote_ip": self.remote_ip_var.get(),
                "remote_port": self.remote_port_var.get(),
                "auto_responses": self.auto_responses,
                "auto_response_enabled": self.auto_response_enabled.get(),
                "shortcut_commands": self.shortcut_commands,
                "display_mode": self.display_mode_var.get(),
                "hex_send": self.hex_send_var.get(),
                "append_newline": self.append_newline_var.get(),
                "timestamp": self.timestamp_var.get(),
                "debug_mode": self.debug_mode_var.get()
            }
            
            with open("network_debugger_config.json", "w", encoding="utf-8") as f:
                json.dump(config, f, ensure_ascii=False, indent=2)
            
            self.log_debug("配置已保存")
        except Exception as e:
            self.log_debug(f"保存配置错误: {str(e)}")
    
    def load_config(self):
        """从文件加载配置"""
        try:
            if os.path.exists("network_debugger_config.json"):
                with open("network_debugger_config.json", "r", encoding="utf-8") as f:
                    config = json.load(f)
                
                # 恢复配置
                self.protocol_var.set(config.get("protocol", "TCP"))
                self.mode_var.set(config.get("mode", "客户端"))
                self.local_ip_var.set(config.get("local_ip", "0.0.0.0"))
                self.local_port_var.set(config.get("local_port", "8080"))
                self.remote_ip_var.set(config.get("remote_ip", "127.0.0.1"))
                self.remote_port_var.set(config.get("remote_port", "8080"))
                
                # 恢复自动应答规则
                if "auto_responses" in config and isinstance(config["auto_responses"], list):
                    self.auto_responses = config["auto_responses"]
                    # 确保包含新的Hex相关字段
                    for rule in self.auto_responses:
                        # 重命名旧字段（如果存在）
                        if "pattern_is_ascii" in rule:
                            rule["pattern_is_hex"] = not rule.pop("pattern_is_ascii")
                        if "response_is_ascii" in rule:
                            rule["response_is_hex"] = not rule.pop("response_is_ascii")
                        # 添加缓冲区字段
                        if "pattern_buffer" not in rule:
                            rule["pattern_buffer"] = rule.get("pattern", "")
                        if "response_buffer" not in rule:
                            rule["response_buffer"] = rule.get("response", "")
                    # 确保至少有一个规则
                    if not self.auto_responses:
                        self.add_response_rule()
                    self.update_response_rules_ui()
                
                # 恢复快捷指令
                if "shortcut_commands" in config and isinstance(config["shortcut_commands"], list):
                    self.shortcut_commands = config["shortcut_commands"]
                    # 确保包含缓冲区字段
                    for cmd in self.shortcut_commands:
                        if "temp_buffer" not in cmd:
                            cmd["temp_buffer"] = cmd.get("content", "")
                    # 确保至少有一个指令
                    if not self.shortcut_commands:
                        self.add_shortcut_command()
                    self.update_shortcut_commands_ui()
                
                # 恢复其他设置
                self.auto_response_enabled.set(config.get("auto_response_enabled", False))
                self.display_mode_var.set(config.get("display_mode", "ASCII"))
                self.hex_send_var.set(config.get("hex_send", False))
                self.append_newline_var.set(config.get("append_newline", True))
                self.timestamp_var.set(config.get("timestamp", True))
                self.debug_mode_var.set(config.get("debug_mode", False))
                
                self.log_debug("配置已加载")
        except Exception as e:
            self.log_debug(f"加载配置错误: {str(e)}")
    
    # ---------------------- 窗口事件处理 ----------------------
    def on_closing(self):
        """窗口关闭事件处理"""
        if self.running:
            if messagebox.askyesno("确认", "当前仍在运行中，确定要关闭吗?"):
                self.stop()
                self.root.destroy()
        else:
            self.root.destroy()

if __name__ == "__main__":
    root = tk.Tk()
    app = NetworkDebugger(root)
    root.mainloop()
    